package com.fyh.service.impl;

import com.fyh.entity.common.Result;
import com.fyh.entity.community.*;
import com.fyh.feign.CommunityUserFeignClient;
import com.fyh.feign.fallback.CommunityUserFeignClientFallback;
import com.fyh.mapper.CommunityMapper;
import com.fyh.service.CommunityService;
import com.fyh.util.OssUtil;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Array;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class CommunityServiceImpl implements CommunityService {

    @Autowired
    CommunityMapper communityMapper;
    @Autowired
    RedisTemplate<String, Object> redisTemplate;
    @Qualifier("com.fyh.feign.CommunityUserFeignClient")
    @Autowired
    CommunityUserFeignClient communityUserFeignClient;

    private static final int PAGE_SIZE = 10;

    private static final String POST_STATISTICS_KEY = "post_statistics:";

    private static final String REPLY_STATISTICS_KEY = "reply_statistics:";

    /**
     * 获取所有帖子类型分类
     *
     * @return
     */
    @Override
    public List<Category> getCategoryList() {
        List<Category> categoryList = communityMapper.getCategoryList();
        return categoryList;
    }

    /**
     * 上传帖子附件
     *
     * @param file
     * @return
     */
    @Override
    public String uploadAttachment(MultipartFile file) {
        try {
            // 获取原始文件名
            String originalFilename = file.getOriginalFilename();
            // 获取文件后缀
            String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
            // 生成新的文件名
            String fileName = UUID.randomUUID() + suffix;
            // 上传文件
            String filePath = OssUtil.uploadFile(fileName, file.getBytes());
            return filePath;
        } catch (Exception e) {
            log.warn("上传文件失败:{}", e);
        }
        return null;
    }

    /**
     * 发布帖子
     *
     * @param postVO
     */
    @Override
    @Transactional
    public void addPost(PostVO postVO) {
        postVO.setCreateTime(LocalDateTime.now());
        postVO.setUpdateTime(LocalDateTime.now());
        // 插入帖子记录表
        communityMapper.insertPost(postVO);
        // 插入帖子附件表
        if(postVO.getAttachmentPathList() != null){
            communityMapper.insertAttachmentPathList(postVO.getPostId(), postVO.getAttachmentPathList());
        }
    }

    /**
     * 获取帖子列表
     *
     * @param postPageDTO
     * @return
     */
    @Override
    public List<PostVO> getPostList(PostPageDTO postPageDTO) {
        // 获取帖子列表(根据分类，关键词搜索，进行排序)
        PageHelper.offsetPage(postPageDTO.getOffset(), PAGE_SIZE);
        List<PostVO> postVOList = communityMapper.getPostList(postPageDTO);
        // 为每个帖子添加点赞数、收藏数、回复数、是否收藏、互动类型
        for(PostVO postVO : postVOList){
            // 为每个帖子添加统计数据
            PostStatistics postStatisticsBatch = getPostStatisticsBatch(postVO);
            postVO.setLikeCount(postStatisticsBatch.getLikeCount());
            postVO.setFavouriteCount(postStatisticsBatch.getFavouriteCount());
            postVO.setReplyCount(postStatisticsBatch.getReplyCount());
            postVO.setCategoryName(postStatisticsBatch.getCategoryName());
            // 获取帖子是否收藏
            postVO.setIsFavourite(communityMapper.getIsFavourite(postPageDTO.getUserId(), postVO.getPostId()));
            // 获取帖子互动类型
            postVO.setReactionType(communityMapper.getReactionType(postPageDTO.getUserId(), postVO.getPostId(), null));

            //删减帖子内容
            if(postVO.getContent().length() > 50) {
                postVO.setContent(postVO.getContent().substring(0, 50) + "...");
            }
        }
        //补全发布者昵称和头像路径
        postVOList = communityUserFeignClient.selectNicknameAndAvaterPathForPost(postVOList).getData();
        return postVOList;
    }

    /**
     * 交互（点赞，点踩，取消）
     * @param reactionDTO
     * @return
     * postId和replyId不能同时为空或者同时存在
     */
    @Override
    @Transactional
    public void reaction(ReactionDTO reactionDTO) {
        reactionDTO.setReactionTime(LocalDateTime.now());

        communityMapper.deleteReactionRecord(reactionDTO);
        String reactionType = reactionDTO.getReactionType();
        if(reactionType.contains("->")){
            reactionDTO.setReactionType(reactionType.split("->")[1]);
        }
        if(!reactionDTO.getReactionType().startsWith("cancel")){
            communityMapper.insertReactionRecord(reactionDTO);

        }
        reactionDTO.setReactionType(reactionType);
        // 更新统计数据缓存
        if(reactionDTO.getPostId() != null){
            //帖子
            String cacheKey = POST_STATISTICS_KEY + reactionDTO.getPostId();
            PostStatistics postStatistics = (PostStatistics) redisTemplate.opsForValue().get(cacheKey);
            if(postStatistics != null){
                postStatistics.setLikeCount(communityMapper.getPostLikeCount(reactionDTO.getPostId()));
                postStatistics.setDislikeCount(communityMapper.getPostDislikeCount(reactionDTO.getPostId()));
                redisTemplate.opsForValue().set(cacheKey, postStatistics);
            }
            // 更新热度
            updatePostHeat(reactionDTO.getPostId());
        }
        else{
            // 回复
            String cacheKey = REPLY_STATISTICS_KEY + reactionDTO.getReplyId();
            ReplyStatistics replyStatistics = (ReplyStatistics) redisTemplate.opsForValue().get(cacheKey);
            if(replyStatistics != null){
                log.info(reactionDTO.getReactionType());
                replyStatistics.setDislikeCount(communityMapper.getReplyDislikeCount(reactionDTO.getReplyId()));
                replyStatistics.setLikeCount(communityMapper.getReplyLikeCount(reactionDTO.getReplyId()));
                redisTemplate.opsForValue().set(cacheKey, replyStatistics);
            }
            // 更新热度
            updateReplyHeat(reactionDTO.getReplyId());
        }

    }

    /**
     * （取消）收藏帖子
     * @param reactionDTO
     */
    @Override
    public void favorite(ReactionDTO reactionDTO) {
        reactionDTO.setReactionTime(LocalDateTime.now());
        String cacheKey = POST_STATISTICS_KEY + reactionDTO.getPostId();
        PostStatistics postStatistics = (PostStatistics) redisTemplate.opsForValue().get(cacheKey);
        if(reactionDTO.getReactionType().equals("favorite")){
            communityMapper.insertFavorite(reactionDTO);
            if(postStatistics != null){
                postStatistics.setFavouriteCount(postStatistics.getFavouriteCount() + 1);
            }
        }
        else{
            communityMapper.deleteFavorite(reactionDTO);
            if(postStatistics != null){
                postStatistics.setFavouriteCount(postStatistics.getFavouriteCount() - 1);
            }
        }
        redisTemplate.opsForValue().set(cacheKey, postStatistics);
        //更新帖子热度
        updatePostHeat(reactionDTO.getPostId());
    }

    /**
     * 获取帖子详情
     * @param postId
     * @return
     */
    @Override
    public PostVO getPostDetail(Long postId, Long userId) {
        PostVO postVO = communityMapper.getPostDetail(postId);
        // 获取用户昵称和头像
        postVO = communityUserFeignClient.selectNicknameAndAvaterPathForPost(Arrays.asList(postVO)).getData().get(0);
        // 获取帖子统计数据
        PostStatistics postStatistics = getPostStatisticsBatch(postVO);
        postVO.setLikeCount(postStatistics.getLikeCount());
        postVO.setReplyCount(postStatistics.getReplyCount());
        postVO.setFavouriteCount(postStatistics.getFavouriteCount());
        // 获取帖子类型名
        postVO.setCategoryName(postStatistics.getCategoryName());
        // 获取用户交互类型
        postVO.setReactionType(communityMapper.getReactionType(postVO.getUserId(), postVO.getPostId(), null));
        // 获取帖子是否收藏
        postVO.setIsFavourite(communityMapper.getIsFavourite(postVO.getUserId(), postVO.getPostId()));
        // 获取帖子附件地址列表
        postVO.setAttachmentPathList(communityMapper.selectAttachmentPathList(postVO.getPostId()));
        return postVO;
    }

    /**
     * 获取帖子一级回复列表（分页查询）
     * @param replyPageDTO
     * @return
     */
    @Override
    public List<ReplyVO> getReplyListByPostId(ReplyPageDTO replyPageDTO) {
        PageHelper.offsetPage(replyPageDTO.getOffset(), PAGE_SIZE);
        List<ReplyVO> replyVOList = communityMapper.getReplyListByPostId(replyPageDTO.getPostId());
        //补全用户昵称和头像
        replyVOList = communityUserFeignClient.selectNicknameAndAvaterPathForReply(replyVOList).getData();
        for(ReplyVO replyVO : replyVOList){
            //获取点赞数和评论数
            ReplyStatistics replyStatistics = getReplyStatisticsBatch(replyVO);
            replyVO.setLikeCount(replyStatistics.getLikeCount());
            replyVO.setReplyCount(replyStatistics.getReplyCount());
            //获取当前用户互动状态
            replyVO.setReactionType(communityMapper.getReactionType(replyPageDTO.getUserId(), null, replyVO.getReplyId()));
        }
        return replyVOList;
    }

    /**
     * 获取帖子二级回复列表（分页查询）
     * @param replyPageDTO
     * @return
     */
    @Override
    public List<ReplyVO> getReplyReplyList(ReplyPageDTO replyPageDTO) {
        PageHelper.offsetPage(replyPageDTO.getOffset(), 5);
        List<ReplyVO> replyVOList = communityMapper.getReplyReplyList(replyPageDTO);
        //补全用户昵称和头像
        replyVOList = communityUserFeignClient.selectNicknameAndAvaterPathForReply(replyVOList).getData();
        for(ReplyVO replyVO : replyVOList){
            //获取点赞数和评论数
            ReplyStatistics replyStatistics = getReplyStatisticsBatch(replyVO);
            replyVO.setLikeCount(replyStatistics.getLikeCount());
            replyVO.setReplyCount(replyStatistics.getReplyCount());
            //获取当前用户互动状态
            replyVO.setReactionType(communityMapper.getReactionType(replyPageDTO.getUserId(), null, replyVO.getReplyId()));
        }
        return replyVOList;
    }

    /**
     * 发表回复
     * @param replyDTO
     */
    @Override
    public void addReply(ReplyDTO replyDTO) {
        replyDTO.setCreateTime(LocalDateTime.now());
        communityMapper.insertReply(replyDTO);
        // 修改帖子回复数的缓存数据
        String postCacheKey = POST_STATISTICS_KEY + replyDTO.getPostId();
        PostStatistics postStatistics = (PostStatistics) redisTemplate.opsForValue().get(postCacheKey);
        postStatistics.setReplyCount(postStatistics.getReplyCount() + 1);
        redisTemplate.opsForValue().set(postCacheKey, postStatistics);

        if(replyDTO.getParentId() != null){
            // 修改父级回复的回复数缓存数据
            String replyCacheKey = REPLY_STATISTICS_KEY + replyDTO.getParentId();
            ReplyStatistics replyStatistics = (ReplyStatistics) redisTemplate.opsForValue().get(replyCacheKey);
            replyStatistics.setReplyCount(replyStatistics.getReplyCount() + 1);
            redisTemplate.opsForValue().set(replyCacheKey, replyStatistics);
        }
    }

    /**
     * 为帖子添加统计数据
     *
     * @param postVO
     * @return
     */
    private PostStatistics getPostStatisticsBatch(PostVO postVO){
        // 生成缓存键
        String cacheKey = POST_STATISTICS_KEY + postVO.getPostId();
        // 尝试从缓存中获取数据
        PostStatistics postStatistics = (PostStatistics) redisTemplate.opsForValue().get(cacheKey);
        if(postStatistics == null){
            postStatistics = new PostStatistics();
            // 获取帖子点赞数
            postStatistics.setLikeCount(communityMapper.getPostLikeCount(postVO.getPostId()));
            // 获取帖子点踩数
            postStatistics.setDislikeCount(communityMapper.getPostDislikeCount(postVO.getPostId()));
            // 获取帖子收藏数
            postStatistics.setFavouriteCount(communityMapper.getPostFavouriteCount(postVO.getPostId()));
            // 获取帖子回复数
            postStatistics.setReplyCount(communityMapper.getPostReplyCount(postVO.getPostId()));
            // 获取帖子类型
            postStatistics.setCategoryName(communityMapper.getCategoryName(postVO.getCategoryId()));
            // 将统计数据存入缓存
            redisTemplate.opsForValue().set(cacheKey, postStatistics, Duration.ofMinutes(10));
        }
        return postStatistics;
    }


    private ReplyStatistics getReplyStatisticsBatch(ReplyVO replyVO) {
        // 生成缓存键
        String cacheKey = REPLY_STATISTICS_KEY + replyVO.getReplyId();
        // 从缓存中获取数据
        ReplyStatistics replyStatistics = (ReplyStatistics) redisTemplate.opsForValue().get(cacheKey);
        if(replyStatistics == null){
            //实例化对象
            replyStatistics = new ReplyStatistics();
            // 获取回复点赞数
            replyStatistics.setLikeCount(communityMapper.getReplyLikeCount(replyVO.getReplyId()));
            // 获取回复踩数
            replyStatistics.setDislikeCount(communityMapper.getReplyDislikeCount(replyVO.getReplyId()));
            // 获取回复回复数
            if(replyVO.getParentId() == null){
                replyStatistics.setReplyCount(communityMapper.getReplyReplyCount(replyVO.getReplyId()));
            }
            // 缓存回复统计数据
            redisTemplate.opsForValue().set(cacheKey, replyStatistics);
        }
        return replyStatistics;
    }

    /**
     * 更新帖子热度
     *
     * @param postId
     */
    private void updatePostHeat(Long postId) {
        String cacheKey = POST_STATISTICS_KEY + postId;
        PostStatistics postStatistics = (PostStatistics) redisTemplate.opsForValue().get(cacheKey);
        //修改帖子热度
        communityMapper.updatePostHeat(postId, postStatistics.getLikeCount() + postStatistics.getReplyCount() + postStatistics.getFavouriteCount() - postStatistics.getDislikeCount());
    }

    /**
     * 更新回复热度
     *
     * @param replyId
     */
    private void updateReplyHeat(Long replyId) {
        String cacheKey = REPLY_STATISTICS_KEY + replyId;
        ReplyStatistics replyStatistics = (ReplyStatistics) redisTemplate.opsForValue().get(cacheKey);
        //修改回复热度
        if(replyStatistics.getReplyCount() != null){
            communityMapper.updateReplyHeat(replyId, replyStatistics.getLikeCount() + replyStatistics.getReplyCount() - replyStatistics.getDislikeCount());
        }
    }


}
